package com.dodayum.service;

import com.dodayum.dao.BigDataDemo;
import com.dodayum.mapper.BigDataDemoMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class BigDataDemoServiceImpl {

    private static final int poolSize = 20;

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            poolSize,// 最小线程数
            poolSize, // 最大线程数
            200, // 线程池存活时间
            TimeUnit.MILLISECONDS, //线程池存活时间单位
            new ArrayBlockingQueue<>(20),// 队列
            threadFactory,// 线程池工厂
            rejectedExecutionHandler// 拒绝策略
    );

    private static final ThreadFactory threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            int index = new AtomicInteger().incrementAndGet();
            return new Thread(r, "当前线程id:Thread-" + index);
        }
    };
    private static final RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            int corePoolSize = executor.getCorePoolSize();
            int maximumPoolSize = executor.getMaximumPoolSize();
            System.out.println("当前线程数：" + corePoolSize + ",最大线程数：" + maximumPoolSize);
        }
    };

    @Resource
    BigDataDemoMapper bigDataDemoMapper;

    public List<BigDataDemo> selectAll() {
        long start = System.nanoTime();
        int pageNumber = 1;
        int pageSize = 2000;
        List<BigDataDemo> response = new ArrayList<>();
        while (true) {
            List<BigDataDemo> newList = bigDataDemoMapper.queryByPage(null, (pageNumber - 1) * pageSize, pageSize);
            if (newList.size() != 0) {
                response.addAll(newList);
                System.out.println("完成第" + pageNumber + "页\t" + response.size());
                pageNumber += 1;
            } else {
                break;
            }
        }
        long end = System.nanoTime();
        System.out.println((end - start) / 1000000 + "毫秒");
        System.out.println(response.size());
        return response;
    }

    public String buildDemoData() {
        int maxThreadPool = threadPoolExecutor.getMaximumPoolSize() == 0 ? 1 : threadPoolExecutor.getMaximumPoolSize();
        int hasSize = bigDataDemoMapper.queryCount(); // 现在数据库里已经有的
        int wantInsertSize = 10000000 - hasSize; // 69231 100000000
        if (wantInsertSize <= 0) {
            return "数据量够用，不用执行";
        }
        List<Integer> jobs = new ArrayList<>();

        // 根据最大线程数量进行分组
        if (wantInsertSize > maxThreadPool) {
            int a = wantInsertSize / maxThreadPool; // 每个线程至少要执行的任务数
            int b = wantInsertSize % maxThreadPool; // 需要其他线程去平分
            for (int i = 0; i < maxThreadPool; i++) {
                jobs.add(a);
            }
            for (int i = 0; i < b; i++) {
                Integer i1 = jobs.get(i);
                jobs.set(i, i1 + 1);
            }
        } else {
            for (int i = 0; i < wantInsertSize; i++) {
                jobs.add(1);
            }
        }

        for (Integer job : jobs) {
            threadPoolExecutor.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i < job; i++) {
                                BigDataDemo bigDataDemo = new BigDataDemo();
                                bigDataDemo.setName("demo");
                                bigDataDemo.setCreateTime(new Date());
                                bigDataDemo.setSeq(String.valueOf(System.currentTimeMillis()));
                                bigDataDemoMapper.insert(bigDataDemo);
                            }
                        }
                    }
            );
        }

        return "成功，需要添加数据量：" + wantInsertSize;
    }

    public String getThreadRunInfo() {
        int poolSize = threadPoolExecutor.getActiveCount();
        return String.valueOf(poolSize);
    }
}
